package typeassert

import (
	"fmt"
	"github.com/mitchellh/mapstructure"
)

// 定义常量动物类型
const (
	Canidae     int = iota + 1 // 猫科动物
	Felidae                    // 犬科动物
	Phasianidae                // 雉科动物
)

// AnimalInfo 动物信息
type AnimalInfo interface {
	AddInfo()
	GetInfo()
}

// ************************************************** Dog Type *********************************************************

// Dog 狗的信息
type Dog struct {
	Name     string
	Type     int
	Age      int
	Favorite []string
}

// GetInfo 获取狗的信息
func (d *Dog) GetInfo() {
	fmt.Println("姓名\t年龄\t爱好")
	fmt.Printf("%s\t%d\t%v\n", d.Name, d.Age, d.Favorite)
}

// AddInfo 添加狗的信息
func (d *Dog) AddInfo() {
	d.Name = "史努比"
	d.Type = Felidae
	d.Age = 14
	d.Favorite = []string{"吃饭睡觉打豆豆"}
}

// ************************************************** Tiger Type *******************************************************

// Tiger 老虎的信息
type Tiger struct {
	Name          string   // 姓名
	Type          int      // 类别
	Age           int      // 年龄
	Sex           string   // 性别
	Weight        float64  // 体重
	Area          string   // 老家
	Favorite      []string // 爱好
	MaritalStatus bool     // 婚姻情况
	ChildStatus   bool     // 子女情况
	ChildNum      int      // 孩子数量
	IsProtect     bool     // 是否是保护动物
	ProtectLevel  string   // 保护级别
}

// AddInfo 添加老虎的信息
func (t *Tiger) AddInfo() {
	t.Name = "孬孬"
	t.Type = Canidae
	t.Age = 12
	t.Sex = "雄虎"
	t.Weight = 287.89
	t.Area = "西西伯利亚"
	t.Favorite = []string{"牛肉", "三文鱼", "睡觉"}
	t.MaritalStatus = false
	t.ChildStatus = false
	t.IsProtect = true
	t.ProtectLevel = "国家二级保护动物"
}

// GetInfo 获取老虎的信息
func (t *Tiger) GetInfo() {
	fmt.Printf("姓名\t年龄\t性别\t体重\t老家\t爱好\t婚姻状况\t子女情况\t孩子数量\t保护动物\t保护级别\n")
	fmt.Printf("%s\t%d\t%s\t%f\t%s\t%v\t%t\t%t\t%d\t%t\t%s\n", t.Name, t.Age, t.Sex, t.Weight, t.Area, t.Favorite, t.MaritalStatus, t.ChildStatus, t.ChildNum, t.IsProtect, t.ProtectLevel)
}

// ************************************************** ZhiYin type ******************************************************

// Chicken 鸡的信息
type Chicken struct {
	Name     string   // 姓名
	Type     int      // 类别
	NickName string   // 别名
	Age      int      // 年龄
	Sex      string   // 性别
	Favorite []string // 爱好
	FansNum  int      // 粉丝数量
}

// AddInfo 添加鸡的信息
func (c *Chicken) AddInfo() {
	c.Name = "蔡徐坤"
	c.Type = Phasianidae
	c.Sex = "公鸡"
	c.NickName = "只因咯咯"
	c.Age = 25
	c.Favorite = []string{"唱", "跳", "rap", "篮球"}
	c.FansNum = 4000
}

// GetInfo 获取鸡的信息
func (c *Chicken) GetInfo() {
	fmt.Println("姓名\t别名\t年龄\t性别\t爱好\t粉丝数量")
	fmt.Printf("%s\t%s\t%d\t%s\t%v\t%d\n", c.Name, c.NickName, c.Age, c.Sex, c.Favorite, c.FansNum)
}

// ************************************************** Assert Logic *****************************************************

// MainRun 主运行方法
func MainRun() {
	// getAnimalInfo()
	getMapAnimalInfo()
}

// SpecialInformation 物种信息
type SpecialInformation struct {
	SpecialType int
	SpecialInfo interface{}
}

// getAnimalInfo 获取张三的信息
func getAnimalInfo() {
	tiger := &Tiger{}
	// 获取老虎信息
	TigerInfo := &SpecialInformation{
		SpecialType: Canidae,
		SpecialInfo: *tiger,
	}
	TypeAssert(TigerInfo.SpecialInfo)
	// 获取狗的信息
	dog := &Dog{}
	DogInfo := &SpecialInformation{
		SpecialType: Felidae,
		SpecialInfo: *dog,
	}
	TypeAssert(DogInfo.SpecialInfo)

	// 获取鸡的信息
	chicken := &Chicken{}
	ChickenInfo := &SpecialInformation{
		SpecialType: Phasianidae,
		SpecialInfo: *chicken,
	}
	TypeAssert(ChickenInfo.SpecialInfo)
}

// getMapAnimalInfo 获取map信息
func getMapAnimalInfo() {
	// 老虎信息
	tigerInfo := map[string]interface{}{
		"type":          Canidae,
		"name":          "麟麟",
		"age":           12,
		"sex":           "雄虎",
		"weight":        287.89,
		"area":          "西西伯利亚",
		"favorite":      []string{"牛肉", "三文鱼", "睡觉"},
		"maritalStatus": false,
		"childStatus":   false,
		"isProtect":     true,
		"protectLevel":  "国家二级保护动物",
	}
	tiger := &SpecialInformation{SpecialType: Canidae, SpecialInfo: tigerInfo}
	TypeAssert(tiger.SpecialInfo)
}

// mapFormatStruct map转换成结构体
func mapFormatStruct(info map[string]interface{}) AnimalInfo {
	var animalInfo AnimalInfo
	animalType, ok := info["type"].(int)
	if !ok {
		fmt.Println("缺少类型字段 type或类型不正确")
	}
	switch animalType {
	case Canidae:
		var decodedInfo Tiger
		err := mapstructure.Decode(info, &decodedInfo)
		if err == nil {
			animalInfo = &decodedInfo
		} else {
			fmt.Println(err)
		}
	case Felidae:
		var decodedInfo Dog
		err := mapstructure.Decode(info, &decodedInfo)
		if err == nil {
			animalInfo = &decodedInfo
		} else {
			fmt.Println(err)
		}
	case Phasianidae:
		var decodedInfo Chicken
		err := mapstructure.Decode(info, &decodedInfo)
		if err == nil {
			animalInfo = &decodedInfo
		} else {
			fmt.Println(err)
		}
	default:
		fmt.Println("未知的动物类型:", animalType)
	}
	return animalInfo
}

// TypeAssert 对于传入的接口对应结构体进行断言
func TypeAssert(animalInfo interface{}) {
	fmt.Println("源数据:", animalInfo)
	switch info := animalInfo.(type) {
	case Dog:
		info.AddInfo()
		info.GetInfo()
	case Tiger:
		info.AddInfo()
		info.GetInfo()
	case Chicken:
		info.AddInfo()
		info.GetInfo()
	case map[string]interface{}:
		decodedInfo := mapFormatStruct(info)
		if decodedInfo == nil {
			fmt.Println("转换失败!", decodedInfo)
		}
		decodedInfo.GetInfo()
	default:
		fmt.Printf("未知类型%T,断言失败!\n", info)
	}
}
